home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / MacHacksBug / Python 1.5.2c1 / Mac / Tools / IDE / PyDocSearch.py < prev    next >
Encoding:
Python Source  |  2000-06-23  |  7.7 KB  |  291 lines

  1. import aetools
  2. import Standard_Suite
  3. import Required_Suite
  4. import WWW_Suite
  5. import regex
  6. import W
  7. import macfs
  8. import os
  9. import MacPrefs
  10. import MacOS
  11. import string
  12.  
  13. if hasattr(WWW_Suite, "WWW_Suite"):
  14.     WWW = WWW_Suite.WWW_Suite
  15. else:
  16.     WWW = WWW_Suite.WorldWideWeb_suite_2c__as_defined_in_Spyglass_spec_2e_
  17.  
  18. class WebBrowser(aetools.TalkTo, 
  19.         Standard_Suite.Standard_Suite, 
  20.         WWW):
  21.     
  22.     def openfile(self, path, activate = 1):
  23.         if activate:
  24.             self.activate()
  25.         self.OpenURL("file:///" + string.join(string.split(path,':'), '/'))
  26.  
  27. app = W.getapplication()
  28.  
  29. #SIGNATURE='MSIE' # MS Explorer
  30. SIGNATURE='MOSS' # Netscape
  31.  
  32. _titlepat = regex.compile('<title>\([^<]*\)</title>')
  33.  
  34. def sucktitle(path):
  35.     f = open(path)
  36.     text = f.read(1024) # assume the title is in the first 1024 bytes
  37.     f.close()
  38.     lowertext = string.lower(text)
  39.     if _titlepat.search(lowertext) > 0:
  40.         a, b = _titlepat.regs[1]
  41.         return text[a:b]
  42.     return path
  43.  
  44. def verifydocpath(docpath):
  45.     try:
  46.         tut = os.path.join(docpath, "tut")
  47.         lib = os.path.join(docpath, "lib")
  48.         ref = os.path.join(docpath, "ref")
  49.         for path in [tut, lib, ref]:
  50.             if not os.path.exists(path):
  51.                 return 0
  52.     except:
  53.         return 0
  54.     return 1
  55.  
  56.  
  57. class TwoLineList(W.List):
  58.     
  59.     LDEF_ID = 468
  60.     
  61.     def createlist(self):
  62.         import List
  63.         self._calcbounds()
  64.         self.SetPort()
  65.         rect = self._bounds
  66.         rect = rect[0]+1, rect[1]+1, rect[2]-16, rect[3]-1
  67.         self._list = List.LNew(rect, (0, 0, 1, 0), (0, 28), self.LDEF_ID, self._parentwindow.wid,
  68.                     0, 1, 0, 1)
  69.         self.set(self.items)
  70.  
  71.  
  72. _resultscounter = 1
  73.  
  74. class Results:
  75.     
  76.     def __init__(self, hits):
  77.         global _resultscounter
  78.         hits = map(lambda (path, hits): (sucktitle(path), path, hits), hits)
  79.         hits.sort()
  80.         self.hits = hits
  81.         nicehits = map(
  82.                 lambda (title, path, hits):
  83.                 title + '\r' + string.join(
  84.                 map(lambda (c, p): "%s (%d)" % (p, c), hits), ', '), hits)
  85.         nicehits.sort()
  86.         self.w = W.Window((440, 300), "Search results %d" % _resultscounter, minsize = (200, 100))
  87.         self.w.results = TwoLineList((-1, -1, 1, -14), nicehits, self.listhit)
  88.         self.w.open()
  89.         self.w.bind('return', self.listhit)
  90.         self.w.bind('enter', self.listhit)
  91.         _resultscounter = _resultscounter + 1
  92.         self.browser = None
  93.     
  94.     def listhit(self, isdbl = 1):
  95.         if isdbl:
  96.             for i in self.w.results.getselection():
  97.                 if self.browser is None:
  98.                     self.browser = WebBrowser(SIGNATURE, start = 1)
  99.                 self.browser.openfile(self.hits[i][1])
  100.  
  101. class Status:
  102.     
  103.     def __init__(self):
  104.         self.w = W.Dialog((440, 64), "Searching…")
  105.         self.w.searching = W.TextBox((4, 4, -4, 16), "DevDev:PyPyDoc 1.5.1:ext:parseTupleAndKeywords.html")
  106.         self.w.hits = W.TextBox((4, 24, -4, 16), "Hits: 0")
  107.         self.w.canceltip = W.TextBox((4, 44, -4, 16), "Type cmd-period (.) to cancel.")
  108.         self.w.open()
  109.     
  110.     def set(self, path, hits):
  111.         self.w.searching.set(path)
  112.         self.w.hits.set('Hits: ' + `hits`)
  113.         app.breathe()
  114.     
  115.     def close(self):
  116.         self.w.close()
  117.  
  118.  
  119. def match(text, patterns, all):
  120.     hits = []
  121.     hitsappend = hits.append
  122.     stringcount = string.count
  123.     for pat in patterns:
  124.         c = stringcount(text, pat)
  125.         if c > 0:
  126.             hitsappend((c, pat))
  127.         elif all:
  128.             hits[:] = []
  129.             break
  130.     hits.sort()
  131.     hits.reverse()
  132.     return hits
  133.  
  134. def dosearch(docpath, searchstring, settings):
  135.     (docpath, kind, case, word, tut, lib, ref, ext, api) = settings
  136.     books = [(tut, 'tut'), (lib, 'lib'), (ref, 'ref'), (ext, 'ext'), (api, 'api')]
  137.     if not case:
  138.         searchstring = string.lower(searchstring)
  139.     
  140.     if kind == 1:
  141.         patterns = string.split(searchstring)
  142.         all = 1
  143.     elif kind == 2:
  144.         patterns = string.split(searchstring)
  145.         all = 0
  146.     else:
  147.         patterns = [searchstring]
  148.         all = 0 # not relevant
  149.     
  150.     ospathjoin = os.path.join
  151.     stringlower = string.lower
  152.     status = Status()
  153.     statusset = status.set
  154.     _match = match
  155.     _open = open
  156.     hits = {}
  157.     try:
  158.         MacOS.EnableAppswitch(0)
  159.         try:
  160.             for do, name in books:
  161.                 if not do:
  162.                     continue
  163.                 bookpath = ospathjoin(docpath, name)
  164.                 if not os.path.exists(bookpath):
  165.                     continue
  166.                 files = os.listdir(bookpath)
  167.                 for file in files:
  168.                     fullpath = ospathjoin(bookpath, file)
  169.                     if fullpath[-5:] <> '.html':
  170.                         continue
  171.                     statusset(fullpath, len(hits))
  172.                     f = _open(fullpath)
  173.                     text = f.read()
  174.                     if not case:
  175.                         text = stringlower(text)
  176.                     f.close()
  177.                     filehits = _match(text, patterns, all)
  178.                     if filehits:
  179.                         hits[fullpath] = filehits
  180.         finally:
  181.             MacOS.EnableAppswitch(-1)
  182.             status.close()
  183.     except KeyboardInterrupt:
  184.         pass
  185.     hits = hits.items()
  186.     hits.sort()
  187.     return hits
  188.  
  189.  
  190. class PyDocSearch:
  191.     
  192.     def __init__(self):
  193.         prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
  194.         try:
  195.             (docpath, kind, case, word, tut, lib, ref, ext, api) = prefs.docsearchengine
  196.         except:
  197.             (docpath, kind, case, word, tut, lib, ref, ext, api) = prefs.docsearchengine = \
  198.                 ("", 0, 0, 0, 1, 1, 0, 0, 0)
  199.         
  200.         if docpath and not verifydocpath(docpath):
  201.             docpath = ""
  202.         
  203.         self.w = W.Window((400, 200), "Search the Python Documentation")
  204.         self.w.searchtext = W.EditText((10, 10, -100, 20), callback = self.checkbuttons)
  205.         self.w.searchbutton = W.Button((-90, 12, 80, 16), "Search", self.search)
  206.         buttons = []
  207.         
  208.         gutter = 10
  209.         width = 130
  210.         bookstart = width + 2 * gutter
  211.         self.w.phraseradio = W.RadioButton((10, 38, width, 16), "As a phrase", buttons)
  212.         self.w.allwordsradio = W.RadioButton((10, 58, width, 16), "All words", buttons)
  213.         self.w.anywordsradio = W.RadioButton((10, 78, width, 16), "Any word", buttons)
  214.         self.w.casesens = W.CheckBox((10, 98, width, 16), "Case sensitive")
  215.         self.w.wholewords = W.CheckBox((10, 118, width, 16), "Whole words")
  216.         self.w.tutorial = W.CheckBox((bookstart, 38, -10, 16), "Tutorial")
  217.         self.w.library = W.CheckBox((bookstart, 58, -10, 16), "Library reference")
  218.         self.w.langueref = W.CheckBox((bookstart, 78, -10, 16), "Lanuage reference manual")
  219.         self.w.extending = W.CheckBox((bookstart, 98, -10, 16), "Extending & embedding")
  220.         self.w.api = W.CheckBox((bookstart, 118, -10, 16), "C/C++ API")
  221.         
  222.         self.w.setdocfolderbutton = W.Button((10, -30, 80, 16), "Set doc folder", self.setdocpath)
  223.         
  224.         if docpath:
  225.             self.w.setdefaultbutton(self.w.searchbutton)
  226.         else:
  227.             self.w.setdefaultbutton(self.w.setdocfolderbutton)
  228.         
  229.         self.docpath = docpath
  230.         if not docpath:
  231.             docpath = "(please select the Python html documentation folder)"
  232.         self.w.docfolder = W.TextBox((100, -28, -10, 16), docpath)
  233.         
  234.         [self.w.phraseradio, self.w.allwordsradio, self.w.anywordsradio][kind].set(1)
  235.         
  236.         self.w.casesens.set(case)
  237.         self.w.wholewords.set(word)
  238.         self.w.tutorial.set(tut)
  239.         self.w.library.set(lib)
  240.         self.w.langueref.set(ref)
  241.         self.w.extending.set(ext)
  242.         self.w.api.set(api)
  243.         
  244.         self.w.open()
  245.         self.w.wholewords.enable(0)
  246.         self.w.bind('<close>', self.close)
  247.         self.w.searchbutton.enable(0)
  248.     
  249.     def search(self):
  250.         hits = dosearch(self.docpath, self.w.searchtext.get(), self.getsettings())
  251.         if hits:
  252.             Results(hits)
  253.         elif hasattr(MacOS, 'SysBeep'):
  254.             MacOS.SysBeep(0)
  255.         #import PyBrowser
  256.         #PyBrowser.Browser(hits)
  257.     
  258.     def setdocpath(self):
  259.         fss, ok = macfs.GetDirectory()
  260.         if ok:
  261.             docpath = fss.as_pathname()
  262.             if not verifydocpath(docpath):
  263.                 W.Message("This does not seem to be a Python documentation folder...")
  264.             else:
  265.                 self.docpath = docpath
  266.                 self.w.docfolder.set(docpath)
  267.                 self.w.setdefaultbutton(self.w.searchbutton)
  268.     
  269.     def close(self):
  270.         prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
  271.         prefs.docsearchengine = self.getsettings()
  272.     
  273.     def getsettings(self):
  274.         radiobuttons = [self.w.phraseradio, self.w.allwordsradio, self.w.anywordsradio]
  275.         for i in range(3):
  276.             if radiobuttons[i].get():
  277.                 kind = i
  278.                 break
  279.         docpath = self.docpath
  280.         case = self.w.casesens.get()
  281.         word = self.w.wholewords.get()
  282.         tut = self.w.tutorial.get()
  283.         lib = self.w.library.get()
  284.         ref = self.w.langueref.get()
  285.         ext = self.w.extending.get()
  286.         api = self.w.api.get()
  287.         return (docpath, kind, case, word, tut, lib, ref, ext, api)
  288.     
  289.     def checkbuttons(self):
  290.         self.w.searchbutton.enable(not not self.w.searchtext.get())
  291.